/*
K =  696e737069726564

*/

import { createSubkeys, encrypter, getBinary } from "./DES";
import { subkeyconstructioner, decrypter } from "./DES";
import fs from 'fs'
import { HexToBinary, binaryToHex, getBuffer, to16 } from "./DES/utils";

// 未知的比特个数 7 的倍数，e.g：7 14 21 28
const SIZE = 21
const fillCheckBitNumber: '1' | '2' = '1'

const K = '696e737069726564'

// 已知的前N个bit数
const knownK = K.substring(0, K.length - (SIZE / 7 * 2))


// 
const KBinary = getBinary(knownK)


// 密文，解密后的明文：positive
const ciphertext = 'f6daa309a4e78f39'


/**
 * 开始解密
 */
function start() {
  const startTimestamp = Date.now();
  createHypothesisKey(0, 2 ** SIZE - 1)
  const endTimestamp = Date.now();
  console.log(`总用时间：${endTimestamp - startTimestamp}ms`);


  const re = `耗时：${endTimestamp - startTimestamp}ms，校验位使用：方案${fillCheckBitNumber},计算总个数：${2 ** SIZE - 1}`
  fs.writeFileSync(`./recode/${SIZE}_${fillCheckBitNumber}_data.txt`,
    JSON.stringify(re))

}

function createHypothesisKey(beginPos: number, endPos: number) {
  const arr = []
  for (let index = beginPos; index <= endPos; index++) {
    printTip(`进行第${index + 1}次`)
    const startTimestamp = Date.now();
    printTip(`构建猜想密钥中...`)
    let b = to2(index) // 返回7位二进制
    // b = fillCheckBit1(b) // 方案1，补校验位

    if (fillCheckBitNumber === '1') {
      b = fillCheckBit1(b) // 方案1，补校验位
    } else {
      b = fillCheckBit2(b) // 方案2，补校验位
    }

    const hypothesisKey = KBinary + b
    printTip(`构建猜想密钥完成：${hypothesisKey}`)

    // 子密钥组
    const subkeyArr = subkeyconstructioner(hypothesisKey)
    // 解密结果
    printTip(`解密中`)
    const result = decrypter(ciphertext, subkeyArr)
    printTip(`解密结束，机密后的内容：${result}`)

    // 校验
    printTip(`校验中`)
    const verify = textVerify(result)
    printTip(`校验结果: ${verify}`)
    const endTimestamp = Date.now();
    const spendTime = endTimestamp - startTimestamp

    arr.push({
      number: index + 1,
      hypothesisKey,
      result,
      verify,
      spendTime,
    })

  }

  printTip('写入文件')
  fs.writeFileSync(`./recode/${SIZE}_${fillCheckBitNumber}_data.json`, JSON.stringify(arr))
  printTip('写入完成')

  return arr
}

/**
 * 对解密后得内容进行 明文校验
 * @param text 解密后的内容
 * @returns 正确 true, 错误 false
 */
function textVerify(text: string) {
  const regExp = /^[1-9a-zA-Z?!:';.,]*$/g
  const result = text.match(regExp)

  return result !== null ? true : false
}

function printTip(str: string) {
  console.log(`----------- ${str} -----------`);

}

/**
 * 填充校验位，方案1，直接补0
 * @param binary 
 * @returns 
 */
function fillCheckBit1(binary: string) {
  let result = ''
  for (let i = 0; i < binary.length / 7; i++) {
    let value = binary.substring(i * 7, (1 + i) * 7)
    result += value + '0'
  }

  return result
}

/**
 * 填充校验位，方案2。奇数个1补0，偶数个1补1
 * @param binary 
 * @returns 
 */
function fillCheckBit2(binary: string) {
  const obj = {}
  for (let i = 0; i < binary.length; i++) {
    const value = binary.substring(i, i + 1)
    // @ts-ignore
    if (obj[value]) {
      // @ts-ignore
      obj[value]++
    } else {
      // @ts-ignore
      obj[value] = 1
    }
  }
  // @ts-ignore
  if (obj['1'] % 2 === 0) {
    return binary + '1'
  } else {
    return binary + '0'
  }
}

/**
 * 这个方法是提供给 to2 的
 * @param num 
 * @deprecated 不要使用，使用 to2 方法
 * @returns 
 */
function DecimalTransformBinary(num: number): string {
  if (num === 0 || num === 1) return num + ''
  // 余数
  const remainder = num % 2 + ''
  const result = Math.floor(num / 2)

  return DecimalTransformBinary(result) + remainder
}

/**
 * 一个 10 进制 转 2进制
 * @param num 
 * @returns 
 */
export function to2(num: number) {
  let result = DecimalTransformBinary(num)
  const zeros = '0000000000000000000000000000000000000000000000000000000000000000'
  const shortNum = SIZE - result.length
  result = zeros.substring(0, shortNum) + result
  return result
}

// start()


console.log(binaryToHex('0110100101101110011100110111000001101001011100100110010001100100'));


const keyHex = '696e737069726564' // 696e737069726464
const c1 = 'f6daa309a4e78f39'

const key = getBinary(keyHex)
console.log(key,123);

const subKey = subkeyconstructioner(key)
const m = decrypter(c1, subKey)
console.log(m);

/*
[{"number":921547,"SerialNumber":4044,"hypothesisKey":"0110100101101110011100110111000001101001011100000011111010010110","result":"!MXUwVNJ","verify":true,"spendTime":0},
{"number":940338,"SerialNumber":22835,"hypothesisKey":"0110100101101110011100110111000001101001011100100110010001100100","result":"positive","verify":true,"spendTime":0}]

01101001 01101110 01110011 01110000 01101001 01110010 01100101 01100100
01101001 01101110 01110011 01110000 01101001 01110010 01100100 01100100


*/



// console.log(K1);


// const subKey = createSubkeys(c1)
// console.log(subKey);

// console.log(decrypter(c1, subKey));
